﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LevenBlog.Core.Data;
using LevenBlog.Core.Entities;
using LevenBlog.Core.Utils;
using LevenBlog.Core.Cache;

namespace LevenBlog.Core.Service {
    public static class Blog {
        private static readonly string cacheName = "levenblog_servicecache_blog_count_";

        public static lb_blog Get(IDbProvider provider, int id) {
            lb_blog blog = ProviderManager.Factory.Blog.Get(provider, id);
            if (blog == null) {
                return null;
            }
            //blog.hits++;
            //ProviderManager.Factory.Blog.Update(provider, blog);
            ProviderManager.Factory.Blog.AddHits(provider, blog.id, 1);
            blog.Category = Category.Get(provider, blog.categoryid);
            return blog;
        }

        public static Pair<lb_blog, lb_blog> GetAbout(IDbProvider provider, int id) {
            return ProviderManager.Factory.Blog.GetAbout(provider, id);
        }

        public static IList<lb_blog> Get(IDbProvider provider, int pageSize, int currentPage, BlogState selectState) {
            IList<lb_blog> blogList = ProviderManager.Factory.Blog.Get(provider, pageSize, currentPage, selectState);
            FillCategory(provider, blogList);
            return blogList;
        }

        public static IList<lb_blog> Get(IDbProvider provider, int categoryid, int pageSize, int currentPage, BlogState selectState) {
            IList<lb_blog> blogList = ProviderManager.Factory.Blog.Get(provider, categoryid, pageSize, currentPage, selectState);
            FillCategory(provider, blogList);
            return blogList;
        }

        public static IList<lb_blog> Get(IDbProvider provider, DateTime startTime, DateTime endTime, int pageSize, int currentPage, BlogState selectState) {
            IList<lb_blog> blogList = ProviderManager.Factory.Blog.Get(provider, startTime, endTime, pageSize, currentPage, selectState);
            FillCategory(provider, blogList);
            return blogList;
        }

        public static IList<lb_blog> GetFromUser(IDbProvider provider, string postuser, int pageSize, int currentPage, BlogState selectState) {
            IList<lb_blog> blogList = ProviderManager.Factory.Blog.GetFromUser(provider, postuser, pageSize, currentPage, selectState);
            FillCategory(provider, blogList);
            return blogList;
        }

        public static IList<lb_blog> SearchTitle(IDbProvider provider, string searchString, int pageSize, int currentPage, BlogState selectState) {
            IList<lb_blog> blogList = ProviderManager.Factory.Blog.SearchFromTitle(provider, searchString, pageSize, currentPage, selectState);
            FillCategory(provider, blogList);
            return blogList;
        }

        public static IList<lb_blog> SearchTags(IDbProvider provider, string searchTags, int pageSize, int currentPage, BlogState selectState) {
            IList<lb_blog> blogList = ProviderManager.Factory.Blog.SearchFromTags(provider, searchTags, pageSize, currentPage, selectState);
            FillCategory(provider, blogList);
            return blogList;
        }

        public static int Count(IDbProvider provider) {
            int? find = ObjectCache.Get<int?>(cacheName + "0");
            if (find == null) {
                find = ProviderManager.Factory.Blog.Count(provider, BlogState.Show);
                ObjectCache.Insert(cacheName + "0", find);
            }
            return find.Value;
        }

        public static int Count(IDbProvider provider, int categoryid) {
            int? find = ObjectCache.Get<int?>(cacheName + categoryid);
            if (find == null) {
                find = ProviderManager.Factory.Blog.CountFromCategoryID(provider, categoryid, BlogState.Show);
                ObjectCache.Insert(cacheName + categoryid, find);
            }
            return find.Value;
        }

        public static int Count(IDbProvider provider, BlogState selectState) {
            return ProviderManager.Factory.Blog.Count(provider, selectState);
        }

        public static int Count(IDbProvider provider, int categoryid, BlogState selectState) {
            return ProviderManager.Factory.Blog.CountFromCategoryID(provider, categoryid, selectState);
        }

        public static int CountFromDateTime(IDbProvider provider, DateTime startTime, DateTime endTime, BlogState selectState) {
            return ProviderManager.Factory.Blog.CountFromDateTime(provider, startTime, endTime, selectState);
        }

        public static int CountFromUser(IDbProvider provider, string postuser, BlogState selectState) {
            return ProviderManager.Factory.Blog.CountFromUser(provider, postuser, selectState);
        }

        public static int CountFromSearchTitle(IDbProvider provider, string searchString, BlogState selectState) {
            return ProviderManager.Factory.Blog.CountFromSearchTitle(provider, searchString, selectState);
        }

        public static int CountFromSearchTags(IDbProvider provider, string searchTags, BlogState selectState) {
            return ProviderManager.Factory.Blog.CountFromSearchTags(provider, searchTags, selectState);
        }

        public static void Insert(IDbProvider provider, lb_blog blog) {
            CheckBlog(blog);
            provider.BeginTransaction();
            try {
                lb_category category = Category.Get(provider, blog.categoryid);
                category.num++;
                Category.Update(provider, category);
                lb_state state = State.Get(provider);
                state.blognum++;
                State.Update(provider, state);
                lb_user user = ProviderManager.Factory.User.Get(provider, blog.postuser);
                user.postnum++;
                ProviderManager.Factory.User.Update(provider, user);
                Archive.InserOneBlog(provider, blog.posttime.Year, blog.posttime.Month);
                string[] tags = blog.tags.Split(',');
                foreach (string tag in tags) {
                    if (tag.Length > 0)
                        Tag.Add(provider, tag, tag);
                }
                ProviderManager.Factory.Blog.Insert(provider, blog);
                Clear(blog.categoryid);
                Clear(0);
                provider.Commit();
            } catch (Exception e) {
                provider.Rollback();
                throw new Exception("添加新blog失败.", e);
            }
        }

        public static void Update(IDbProvider provider, lb_blog blog) {
            CheckBlog(blog);
            provider.BeginTransaction();
            try {
                lb_blog oldBlog = ProviderManager.Factory.Blog.Get(provider, blog.id);
                if (blog.categoryid != oldBlog.categoryid) {
                    lb_category oldcate = ProviderManager.Factory.Category.Get(provider, oldBlog.categoryid);
                    lb_category newcate = ProviderManager.Factory.Category.Get(provider, blog.categoryid);
                    oldcate.num--;
                    newcate.num++;
                    ProviderManager.Factory.Category.Update(provider, oldcate);
                    ProviderManager.Factory.Category.Update(provider, newcate);
                }
                Tag.Edit(provider, oldBlog.tags.Split(','), blog.tags.Split(','));
                ProviderManager.Factory.Blog.Update(provider, blog);
                provider.Commit();
            } catch {
                provider.Rollback();
                throw;
            }
            Clear();
        }

        public static void Delete(IDbProvider provider, int id) {
            provider.BeginTransaction();
            try {
                //获取要删除的blog信息
                lb_blog blog = ProviderManager.Factory.Blog.Get(provider, id);
                //获取删除blog的category信息并进行修改
                lb_category category = ProviderManager.Factory.Category.Get(provider, blog.categoryid);
                category.num--;
                ProviderManager.Factory.Category.Update(provider, category);
                //修改发布人的发布信息
                lb_user user = ProviderManager.Factory.User.Get(provider, Text.SqlEncode(blog.postuser));
                user.postnum--;
                ProviderManager.Factory.User.Update(provider, user);
                Archive.DeleteOneBlog(provider, blog.posttime.Year, blog.posttime.Month);
                //删除对应的评论和track信息
                int commentNum = ProviderManager.Factory.Comment.Count(provider, id, CommentState.None);
                int trackNum = ProviderManager.Factory.Track.CountFromBlogID(provider, id);
                lb_state state = ProviderManager.Factory.State.Get(provider);
                state.blognum--;
                state.commentnum -= commentNum;
                state.tracknum -= trackNum;
                ProviderManager.Factory.State.Update(provider, state);
                ProviderManager.Factory.Blog.Delete(provider, id);
                ProviderManager.Factory.Comment.DeleteFromBlogID(provider, id);
                ProviderManager.Factory.Track.DeleteFromBlogID(provider, id);
                string[] tags = blog.tags.Split(',');
                foreach (string tag in tags) {
                    if (tag.Length > 0)
                        ProviderManager.Factory.Tag.Delete(provider, Text.SqlEncode(tag));
                }
                provider.Commit();
            } catch {
                provider.Rollback();
                throw;
            }
            Category.Remove();
            Archive.Remove();
            State.Remove();
            Clear();
        }

        public static IList<int> GetWriteDays(IDbProvider provider, int year, int month) {
            return ProviderManager.Factory.Blog.GetWriteDays(provider, year, month);
        }

        public static void Clear() {
            ObjectCache.RegexRemove(cacheName + ".*?");
        }

        public static void Clear(int id) {
            ObjectCache.Remove(cacheName + id);
        }

        private static void FillCategory(IDbProvider provider, IList<lb_blog> blogList) {
            //IList<lb_category> categoryList = ProviderManager.Factory.Category.Get(provider);
            IList<lb_category> categoryList = Category.Get(provider);
            foreach (lb_blog blog in blogList) {
                blog.Category = categoryList.Single(cate => cate.id == blog.categoryid);
            }
        }

        private static void CheckBlog(lb_blog blog) {
            if (string.IsNullOrEmpty(blog.title))
                throw new ArgumentNullException("title");
            if (string.IsNullOrEmpty(blog.intro))
                throw new ArgumentNullException("intro");
            if (string.IsNullOrEmpty(blog.content))
                throw new ArgumentNullException("content");
            if (blog.categoryid < 0)
                throw new ArgumentOutOfRangeException("categoryid");
        }
    }
}
